package repository

import (
	"oa-system/internal/model"
	"oa-system/pkg/errors"

	"gorm.io/gorm"
)

type MenuRepository interface {
	GetAllMenus(page, pageSize int) ([]model.Menu, int64, error)
	GetMenuByID(id uint) (*model.Menu, error)
	CreateMenu(menu *model.Menu) (*model.Menu, error)
	UpdateMenu(menu *model.Menu) (*model.Menu, error)
	DeleteMenu(id uint) error
	GetAllWithRoles(page, pageSize int) ([]model.Menu, int64, error)
	GetUserMenus(userID uint) ([]model.Menu, error)
	AddMenuPermissions(menuID uint, permissions []model.Permission) error
	GetMenuPermissions(menuID uint) ([]model.Permission, error)
}

type menuRepository struct {
	db *gorm.DB
}

func NewMenuRepository(db *gorm.DB) MenuRepository {
	return &menuRepository{db: db}
}

func (r *menuRepository) GetAllMenus(page, pageSize int) ([]model.Menu, int64, error) {
	var menus []model.Menu
	var total int64

	query := r.db.Model(&model.Menu{})

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, errors.NewInternalServerError("获取菜单总数失败", err)
	}

	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Find(&menus).Error; err != nil {
		return nil, 0, errors.NewInternalServerError("获取菜单列表失败", err)
	}

	return menus, total, nil
}

func (r *menuRepository) GetMenuByID(id uint) (*model.Menu, error) {
	var menu model.Menu
	if err := r.db.First(&menu, id).Error; err != nil {
		return nil, errors.NewNotFoundError("菜单不存在", err)
	}
	return &menu, nil
}

func (r *menuRepository) CreateMenu(menu *model.Menu) (*model.Menu, error) {
	if err := r.db.Create(menu).Error; err != nil {
		return nil, errors.NewInternalServerError("创建菜单失败", err)
	}
	return menu, nil
}

func (r *menuRepository) UpdateMenu(menu *model.Menu) (*model.Menu, error) {
	if err := r.db.Save(menu).Error; err != nil {
		return nil, errors.NewInternalServerError("更新菜单失败", err)
	}
	return menu, nil
}

func (r *menuRepository) DeleteMenu(id uint) error {
	return r.db.Transaction(func(tx *gorm.DB) error {
		// 检查是否有子菜单
		var count int64
		if err := tx.Model(&model.Menu{}).Where("parent_id = ?", id).Count(&count).Error; err != nil {
			return errors.NewInternalServerError("检查子菜单失败", err)
		}
		if count > 0 {
			return errors.NewBadRequestError("该菜单下还有子菜单，无法删除", nil)
		}

		// 删除菜单与角色的关联关系
		if err := tx.Where("menu_id = ?", id).Delete(&model.RoleMenu{}).Error; err != nil {
			return errors.NewInternalServerError("删除菜单角色关联失败", err)
		}

		// 删除菜单
		if err := tx.Delete(&model.Menu{}, id).Error; err != nil {
			return errors.NewInternalServerError("删除菜单失败", err)
		}

		return nil
	})
}

func (r *menuRepository) GetAllWithRoles(page, pageSize int) ([]model.Menu, int64, error) {
	var menus []model.Menu
	var total int64

	query := r.db.Model(&model.Menu{}).Preload("Roles")

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, errors.NewInternalServerError("获取菜单总数失败", err)
	}

	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Find(&menus).Error; err != nil {
		return nil, 0, errors.NewInternalServerError("获取菜单列表失败", err)
	}

	return menus, total, nil
}

func (r *menuRepository) GetUserMenus(userID uint) ([]model.Menu, error) {
	var user model.User
	if err := r.db.Preload("Roles").First(&user, userID).Error; err != nil {
		return nil, errors.NewNotFoundError("用户不存在", err)
	}

	var menus []model.Menu
	query := r.db.Model(&model.Menu{}).Preload("PermissionItems")

	// 如果是 ID 为 1 的用户或超级管理员，获取所有菜单
	if userID == 1 || user.IsSuperAdmin() {
		if err := query.Find(&menus).Error; err != nil {
			return nil, errors.NewInternalServerError("获取用户菜单失败", err)
		}
	} else {
		// 普通用户只获取其角色对应的菜单
		if err := query.
			Joins("JOIN role_menus ON menus.id = role_menus.menu_id").
			Joins("JOIN user_roles ON role_menus.role_id = user_roles.role_id").
			Where("user_roles.user_id = ?", userID).
			Distinct().
			Find(&menus).Error; err != nil {
			return nil, errors.NewInternalServerError("获取用户菜单失败", err)
		}
	}

	// 处理权限
	for i := range menus {
		var permissions []string
		if user.IsSuperAdmin() {
			if err := r.db.Model(&model.Permission{}).
				Where("menu_id = ?", menus[i].ID).
				Pluck("code", &permissions).Error; err != nil {
				return nil, errors.NewInternalServerError("获取菜单权限失败", err)
			}
		} else {
			if err := r.db.Model(&model.Permission{}).
				Joins("JOIN role_permissions ON permissions.id = role_permissions.permission_id").
				Joins("JOIN user_roles ON role_permissions.role_id = user_roles.role_id").
				Where("user_roles.user_id = ? AND permissions.menu_id = ?", userID, menus[i].ID).
				Pluck("permissions.code", &permissions).Error; err != nil {
				return nil, errors.NewInternalServerError("获取用户菜单权限失败", err)
			}
		}
		menus[i].SetPermissions(permissions)
	}

	return menus, nil
}

func (r *menuRepository) AddMenuPermissions(menuID uint, newPermissions []model.Permission) error {
	return r.db.Transaction(func(tx *gorm.DB) error {
		// 检查菜单是否存在
		if err := tx.First(&model.Menu{}, menuID).Error; err != nil {
			return errors.NewNotFoundError("菜单不存在", err)
		}

		// 删除旧权限及其角色关联
		if err := tx.Where("menu_id = ?", menuID).Delete(&model.Permission{}).Error; err != nil {
			return errors.NewInternalServerError("删除旧权限失败", err)
		}

		// 创建新权限
		for i := range newPermissions {
			menuIDPtr := menuID
			newPermissions[i].MenuID = &menuIDPtr

			// 保存角色ID
			roleIDs := newPermissions[i].RoleIDs

			// 创建权限
			if err := tx.Create(&newPermissions[i]).Error; err != nil {
				return errors.NewInternalServerError("创建新权限失败", err)
			}

			// 创建权限-角色关联
			for _, roleID := range roleIDs {
				if err := tx.Create(&model.RolePermission{
					RoleID:       roleID,
					PermissionID: newPermissions[i].ID,
				}).Error; err != nil {
					return errors.NewInternalServerError("创建权限角色关联失败", err)
				}
			}
		}

		return nil
	})
}

func (r *menuRepository) GetMenuPermissions(menuID uint) ([]model.Permission, error) {
	var permissions []model.Permission

	if err := r.db.Where("menu_id = ?", menuID).Find(&permissions).Error; err != nil {
		return nil, errors.NewInternalServerError("获取菜单权限失败", err)
	}

	// 获取每个权限关联的角色ID
	for i := range permissions {
		var roleIDs []uint
		if err := r.db.Table("role_permissions").
			Where("permission_id = ?", permissions[i].ID).
			Pluck("role_id", &roleIDs).Error; err != nil {
			return nil, errors.NewInternalServerError("获取权限角色关联失败", err)
		}
		permissions[i].RoleIDs = roleIDs
	}

	return permissions, nil
}
